﻿using System;
using System.Collections.Generic;
using JetBrains.Annotations;

namespace DiffLib
{
    /// <summary>
    /// This static class contains helper methods to easily access <see cref="Diff{T}"/> and <see cref="AlignedDiff{T}"/>.
    /// </summary>
    [PublicAPI]
    public static class Diff
    {
        /// <summary>
        /// Calculates the diff between the two collections and returns it as a collection of <see cref="DiffChange"/> objects.
        /// </summary>
        /// <typeparam name="T">
        /// The type of elements in the two collections.
        /// </typeparam>
        /// <param name="collection1">
        /// The first collection, to compare with <paramref name="collection2"/>.
        /// </param>
        /// <param name="collection2">
        /// The second collection, to compare with <paramref name="collection1"/>.
        /// </param>
        /// <returns>
        /// A collection of <see cref="DiffChange"/> objects.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <para><paramref name="collection1"/> is <c>null</c>.</para>
        /// <para>- or -</para>
        /// <para><paramref name="collection2"/> is <c>null</c>.</para>
        /// </exception>
        [PublicAPI]
        [NotNull]
        public static IEnumerable<DiffChange> Calculate<T>([NotNull] IEnumerable<T> collection1, [NotNull] IEnumerable<T> collection2)
        {
            return new Diff<T>(collection1, collection2);
        }

        /// <summary>
        /// Calculates the diff between the two collections using the specified equality comparer and returns it as a collection of <see cref="DiffChange"/> objects.
        /// </summary>
        /// <typeparam name="T">
        /// The type of elements in the two collections.
        /// </typeparam>
        /// <param name="collection1">
        /// The first collection, to compare with <paramref name="collection2"/>.
        /// </param>
        /// <param name="collection2">
        /// The second collection, to compare with <paramref name="collection1"/>.
        /// </param>
        /// <param name="equalityComparer">
        /// The <see cref="IEqualityComparer{T}"/> object to use when determining which elements in the two collections are equal.
        /// </param>
        /// <returns>
        /// A collection of <see cref="DiffChange"/> objects.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <para><paramref name="collection1"/> is <c>null</c>.</para>
        /// <para>- or -</para>
        /// <para><paramref name="collection2"/> is <c>null</c>.</para>
        /// <para>- or -</para>
        /// <para><paramref name="equalityComparer"/> is <c>null</c>.</para>
        /// </exception>
        [PublicAPI]
        [NotNull]
        public static IEnumerable<DiffChange> Calculate<T>([NotNull] IEnumerable<T> collection1, [NotNull] IEnumerable<T> collection2, [NotNull] IEqualityComparer<T> equalityComparer)
        {
            return new Diff<T>(collection1, collection2, equalityComparer);
        }

        /// <summary>
        /// Calculates the diff between the two collections using the specified equality comparer and returns it as a collection of <see cref="DiffChange"/> objects.
        /// </summary>
        /// <typeparam name="T">
        /// The type of elements in the two collections.
        /// </typeparam>
        /// <param name="collection1">
        /// The first collection, to compare with <paramref name="collection2"/>.
        /// </param>
        /// <param name="collection2">
        /// The second collection, to compare with <paramref name="collection1"/>.
        /// </param>
        /// <param name="equalityComparer">
        /// The <see cref="IEqualityComparer{T}"/> object to use when determining which elements in the two collections are equal.
        /// </param>
        /// <param name="similarityComparer">
        /// The <see cref="ISimilarityComparer{T}"/> object to use when determining which elements are most similar when doing alignments.
        /// </param>
        /// <param name="alignmentFilter">
        /// The <see cref="IAlignmentFilter{T}"/> object to use when determining which elements can be aligned to gether.
        /// </param>
        /// <returns>
        /// A collection of <see cref="DiffChange"/> objects.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <para><paramref name="collection1"/> is <c>null</c>.</para>
        /// <para>- or -</para>
        /// <para><paramref name="collection2"/> is <c>null</c>.</para>
        /// <para>- or -</para>
        /// <para><paramref name="equalityComparer"/> is <c>null</c>.</para>
        /// <para>- or -</para>
        /// <para><paramref name="similarityComparer"/> is <c>null</c>.</para>
        /// <para>- or -</para>
        /// <para><paramref name="alignmentFilter"/> is <c>null</c>.</para>
        /// </exception>
        [PublicAPI]
        [NotNull]
        public static IEnumerable<AlignedDiffChange<T>> Calculate<T>(IEnumerable<T> collection1, IEnumerable<T> collection2, IEqualityComparer<T> equalityComparer, ISimilarityComparer<T> similarityComparer, IAlignmentFilter<T> alignmentFilter)
        {
            return new AlignedDiff<T>(collection1, collection2, equalityComparer, similarityComparer, alignmentFilter);
        }
    }
}
